/**
  ******************************************************************************
  * @file CAN/Normal/main.c 
  * @author  MCD Application Team
  * @version  V3.0.0
  * @date  04/06/2009
  * @brief  Main program body
  ******************************************************************************
  * @copy
  *
  * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
  * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
  * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
  * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
  * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
  * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
  *
  * <h2><center>&copy; COPYRIGHT 2009 STMicroelectronics</center></h2>
  */ 

/* Includes ------------------------------------------------------------------*/
#include <applicfg.h>
#include "stm32f4xx.h"
#include "platform_config.h"

/* test_slaver */
#include "canfestival.h"
#include "Slave.h"
/** @addtogroup StdPeriph_Examples
  * @{
  */

/** @addtogroup CAN_Normal
  * @{
  */ 

/* Private typedef -----------------------------------------------------------*/

/* Private define ------------------------------------------------------------*/
#define TIM5_start TIM5_Configuration

/* Private macro -------------------------------------------------------------*/
#define SEM_NUM 	( 1 )

/* Private variables ---------------------------------------------------------*/
CanTxMsg TxMessage;
CanRxMsg RxMessage;

OS_EVENT *recv_sem;
OS_EVENT *tran_sem;

/* Private function prototypes -----------------------------------------------*/
extern void TIM5_Configuration(void);

static void CAN_Configuration( u8 baudrate );
static u16  test_slave(void);

#define RX_BUF_LEN 		1024
Message rx_msg_buf[RX_BUF_LEN];
u32	rx_save, rx_read;

#define TX_BUF_LEN		1024
u32 tx_save, tx_read;
CanTxMsg tx_msg_buf[TX_BUF_LEN];

/* Private functions ---------------------------------------------------------*/

/**
  * @brief  can_slave_init
  * @param  None
  * @retval None
  */
void can_slave_init(void)
{
	// transmit queue init
	tx_save = 0;
	tx_read = 0;
	// receive  queue init
	rx_save = 0;
	rx_read = 0;

	CAN_Configuration(BAUDRATE_CAN_500k);

	CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE);
}

/**
  * @brief  can_slave_thread
  * @param  None
  * @retval None
  */
void can_recv_thread(void *pdata)
{
	u8 err_sem;
	u32 next;
	Message *pmsg;

	pdata = pdata;

	recv_sem = OSSemCreate(SEM_NUM);  
	tran_sem = OSSemCreate(SEM_NUM);  	
	
	can_slave_init();

	test_slave();

	OSSemSet(recv_sem, 0, &err_sem);
	
	for(;;) // Infinite loop
	{	
		OSSemPend(recv_sem, 0, &err_sem);

		next = rx_read;
		pmsg = &rx_msg_buf[next];

		//GPIO_ToggleBits(GPIOD, GPIO_Pin_0);

		// Disable the Interrupt sources 
		TIM5->DIER &= (u16)~TIM_IT_CC1;
		canDispatch(&TestSlave_Data, pmsg);
		// Enable the Interrupt sources
		TIM5->DIER |= TIM_IT_CC1;

		next++;
		if(next >= RX_BUF_LEN) next = 0;
		rx_read = next;

		OSTimeDly(1);
	}
}

void can_send_thread(void *pdata)
{
	u8 err_sem;
	u32 next;
	u8  mailbox_no;
	CanTxMsg *ptx_msg;

	pdata = pdata;

	OSSemSet(tran_sem, 0, &err_sem);
	
	for(;;)
	{
		
		OSSemPend(tran_sem, 0, &err_sem);

		next = tx_read;
		ptx_msg = &tx_msg_buf[next];

		mailbox_no = CAN_Transmit(CAN1, ptx_msg);
		if(mailbox_no != CAN_NO_MB)
		{
			next++;
			if(next >= TX_BUF_LEN) next = 0;
			tx_read = next;			
		}
		else
		{
			OSSemPost(tran_sem);
		} 

		OSTimeDly(1);
	}		
}


/**
  * @brief  Configures Can.
  * @param  None
  * @retval None
  */
static void CAN_Configuration( u8 baudrate )
{
	GPIO_InitTypeDef GPIO_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	CAN_InitTypeDef CAN_InitStructure;
	CAN_FilterInitTypeDef  CAN_FilterInitStructure;
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);

	NVIC_InitStructure.NVIC_IRQChannel = CAN1_RX0_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);

	// Connect CAN pins to AF9
	GPIO_PinAFConfig(GPIO_CAN, CAN_RX_SOURCE, CAN_AF_PORT);
	GPIO_PinAFConfig(GPIO_CAN, CAN_TX_SOURCE, CAN_AF_PORT); 
	
	// Configure CAN pin: RX
	GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_RX | GPIO_Pin_TX;
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_UP;
    GPIO_Init(GPIO_CAN, &GPIO_InitStructure);

	// CAN register init
	CAN_DeInit(CAN1);
	CAN_StructInit(&CAN_InitStructure);

	// CAN cell init 
	CAN_InitStructure.CAN_TTCM = DISABLE;
	CAN_InitStructure.CAN_ABOM = DISABLE; //DISABLE
	CAN_InitStructure.CAN_AWUM = DISABLE;
	CAN_InitStructure.CAN_NART = ENABLE;
	CAN_InitStructure.CAN_RFLM = DISABLE;
	CAN_InitStructure.CAN_TXFP = DISABLE;
	CAN_InitStructure.CAN_Mode = CAN_Mode_Normal;
	CAN_InitStructure.CAN_SJW = CAN_SJW_1tq;
	CAN_InitStructure.CAN_BS1 = CAN_BS1_10tq;
	CAN_InitStructure.CAN_BS2 = CAN_BS2_3tq;
	CAN_InitStructure.CAN_Prescaler = baudrate;
	CAN_Init(CAN1, &CAN_InitStructure);

	// CAN filter init 
	CAN_SlaveStartBank(0);
	CAN_FIFORelease( CAN1,CAN_FIFO0 );
	CAN_FilterInitStructure.CAN_FilterNumber = 0;
	CAN_FilterInitStructure.CAN_FilterMode  = CAN_FilterMode_IdMask;
	CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_32bit;
	CAN_FilterInitStructure.CAN_FilterIdHigh = 0x0000;
	CAN_FilterInitStructure.CAN_FilterIdLow  = 0x0000;	   		//0x000C;
	CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0x0000;
	CAN_FilterInitStructure.CAN_FilterMaskIdLow  = 0x0000; 		//0x000E;
	CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_FIFO0;
	CAN_FilterInitStructure.CAN_FilterActivation = ENABLE;
	CAN_FilterInit(&CAN_FilterInitStructure);

	// transmit
	TxMessage.StdId = 0x321;
	TxMessage.ExtId = 0x00;
	TxMessage.RTR = CAN_RTR_DATA;
	TxMessage.IDE = CAN_ID_STD;
	TxMessage.DLC = 1;	

	CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE);
}

u8 canSend(CAN_PORT notused, Message *m)
{
	u32	i;
	u32  next;
	CanTxMsg *ptx_msg;
	//static u32 led_state = 0;

	//GPIO_ToggleBits(GPIOB, GPIO_Pin_0);

	next = tx_save + 1;
	if(next >= TX_BUF_LEN) next = 0;
	if(next != tx_read)
	{
		ptx_msg = &tx_msg_buf[tx_save];
		ptx_msg->StdId = m->cob_id;

		if(m->rtr)
  			ptx_msg->RTR = CAN_RTR_REMOTE;
		else
			ptx_msg->RTR = CAN_RTR_DATA;

  		ptx_msg->IDE = CAN_ID_STD;
  		ptx_msg->DLC = m->len;
		for(i = 0; i < m->len; i++)
			ptx_msg->Data[i] = m->data[i];

		tx_save = next;
		
		OSSemPost(tran_sem);	
		
		return 0x00;
	}
	//GPIO_ToggleBits(GPIOD, GPIO_Pin_0);
	/*
	if(++led_state & 0x01)
		GPIO_ResetBits(GPIOD, GPIO_Pin_0);
	else
		GPIO_SetBits(GPIOD, GPIO_Pin_0);
	*/
	return 0xFF;
}

//void can_rx_isr(void)
void CAN1_RX0_IRQHandler(void) 
{
	Message *pmsg;
	u32 i, next;

	CAN_Receive(CAN1, CAN_FIFO0, &RxMessage);

	next = (rx_save + 1) ;
	if(next >= RX_BUF_LEN) next = 0;
	if(next == rx_read)	return;

	//GPIO_ToggleBits(GPIOD, GPIO_Pin_0);

	pmsg = &rx_msg_buf[rx_save];
	pmsg->cob_id = (UNS16)RxMessage.StdId; /**< message's ID */
	if(RxMessage.RTR == CAN_RTR_REMOTE) /**< remote transmission request. (0 if not rtr message, 1 if rtr message) */
	pmsg->rtr = 1;		
	else
	pmsg->rtr = 0;

	pmsg->len  = (UNS8)RxMessage.DLC; /**< message's length (0 to 8) */
	for(i = 0; i < pmsg->len; i++)
	pmsg->data[i] = RxMessage.Data[i];

	rx_save = next;

	OSSemPost(recv_sem);

}

static TimerCallback_t init_callback;

s_BOARD SlaveBoard  = {"0", "500k"};

void help(void)
{
}

/***************************  INIT  *****************************************/
void InitNodes(CO_Data* d, UNS32 id)
{
	/** INITIALISATION SLAVE */
	if(strcmp(SlaveBoard.baudrate, "none"))
	{
		setNodeId(&TestSlave_Data, 2);//2 -> 3

		/* init */
		setState(&TestSlave_Data, Initialisation);
	}
}

static void StartTimerLoop(TimerCallback_t _init_callback) 
{
	init_callback = _init_callback;
	SetAlarm(NULL, 0, init_callback, 0, 0);
	TIM5_start();
}

/***************************  EXIT  *****************************************/
void Exit(CO_Data* d, UNS32 id)
{

}

/****************************************************************************/
/*****************************  test_salve  *********************************/
/****************************************************************************/
static u16 test_slave(void)
{
	if(strcmp(SlaveBoard.baudrate, "none")){
		
		TestSlave_Data.heartbeatError = TestSlave_heartbeatError;
		TestSlave_Data.initialisation = TestSlave_initialisation;
		TestSlave_Data.preOperational = TestSlave_preOperational;
		TestSlave_Data.operational = TestSlave_operational;
		TestSlave_Data.stopped   = TestSlave_stopped;
		TestSlave_Data.post_sync = TestSlave_post_sync;
		TestSlave_Data.post_TPDO = TestSlave_post_TPDO;
		TestSlave_Data.storeODSubIndex = TestSlave_storeODSubIndex;
		TestSlave_Data.post_emcy = TestSlave_post_emcy;
	}

	// Start timer thread
	StartTimerLoop(&InitNodes);

	return 0;
}

/**
  * @}
  */ 

/**
  * @}
  */ 

/******************* (C) COPYRIGHT 2009 STMicroelectronics *****END OF FILE****/
